﻿#region Imports

using System;
using Spring.DataBinding;
using Spring.Validation;
using Spring.Data.NHibernate.Support;
using System.Collections;
using d3PrtDgn.Common.Common;
using d3PrtDgn.Data.Domain.Entity;
using d3PrtDgn.Data.IDAO;

#endregion

namespace d3PrtDgn.Web
{
	/// <summary>
	/// Photo detail page
	/// </summary>
	public partial class Photo : Page
	{
		#region Private fields

        private Data.Domain.Entity.Photo selectedPhoto;
		private IPhotoDao photoDao;
		private Comment newComment;
		private IValidator commentValidator;
		private Vote newVote;

		#endregion

		#region Public properties

		/// <summary>
		/// Sets photo DAO
		/// </summary>
		public IPhotoDao PhotoDao
		{
			set { photoDao = value; }
		}

		/// <summary>
		/// Gest selected photo
		/// </summary>
        public Data.Domain.Entity.Photo SelectedPhoto
		{
			get { return selectedPhoto; }
		}

		/// <summary>
		/// Sets comment validator
		/// </summary>
		public IValidator CommentValidator
		{
			set { commentValidator = value; }
		}

		/// <summary>
		/// Gets new comment
		/// </summary>
		public Comment NewComment
		{
			get { return newComment; }
		}

		/// <summary>
		/// Gets new vote
		/// </summary>
		public Vote NewVote
		{
			get { return newVote; }
		}

		#endregion

		#region Event handlers

		/// <summary>
		/// Handles on load event
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void Page_Load(object sender, EventArgs e)
		{
			SetVisibility();
			if(!IsPostBack)
				InitializeVoteList();
			InitializePhoto();
			InitializeComments();
		}

		/// <summary>
		/// Redirects back to album
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void BackToAlbum(object sender, EventArgs e)
		{
			SetResult("Album");
		}

		/// <summary>
		/// Saves comment
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void Save(object sender, EventArgs e)
		{
			if (SignedInUser.Id > 0 && Validate(NewComment, commentValidator))
			{
				selectedPhoto.Comments.Add(newComment);

				using (new SessionScope())
				{
					photoDao.SaveOrUpdate(selectedPhoto);
				}

				SetResult("Photo");
			}
		}

		/// <summary>
		/// Saves vote
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void SaveVote(object sender, EventArgs e)
		{
			if (SignedInUser.Id > 0)
			{
				selectedPhoto.Votes.Add(newVote);

				using (new SessionScope())
				{
					photoDao.SaveOrUpdate(selectedPhoto);
				}

				SetResult("Photo");
			}
		}

		#endregion

		#region Model Management and Data Binding Methods

		/// <summary>
		/// Initializes data model
		/// </summary>
		protected override void InitializeModel()
		{
			if (Request.Params["photo"] != null)
				selectedPhoto = photoDao.FindByAbbreviation(Request.Params["photo"], SignedInUser);

			newComment = new Comment();
			newComment.User = SignedInUser;
			newComment.Photo = selectedPhoto;

			newVote = new Vote();
			newVote.Photo = selectedPhoto;
			newVote.User = SignedInUser;
		}

		/// <summary>
		/// Loads model to page
		/// </summary>
		/// <param name="savedModel"></param>
		protected override void LoadModel(object savedModel)
		{
			newComment = (Comment)((Hashtable)savedModel)["newComment"];
            selectedPhoto = (Data.Domain.Entity.Photo)((Hashtable)savedModel)["selectedPhoto"];
			newVote = (Vote)((Hashtable)savedModel)["newVote"];
		}

		/// <summary>
		/// Saves model from page
		/// </summary>
		/// <returns></returns>
		protected override object SaveModel()
		{
			Hashtable model = new Hashtable();
			model["newComment"] = newComment;
			model["selectedPhoto"] = selectedPhoto;
			model["newVote"] = newVote;
			return model;
		}

		/// <summary>
		/// Initializes data bindings
		/// </summary>
		protected override void InitializeDataBindings()
		{
			BindingManager.AddBinding("tbContent.Text", "NewComment.Content");
			BindingManager.AddBinding("DateTime.Now", "NewComment.Inserted", BindingDirection.SourceToTarget);
			BindingManager.AddBinding("DateTime.Now", "NewVote.Inserted", BindingDirection.SourceToTarget);
			BindingManager.AddBinding("ddlRating.SelectedValue", "NewVote.Rating", BindingDirection.SourceToTarget);
		}

		#endregion

		#region Private methods

		/// <summary>
		/// Sets panels visibility
		/// </summary>
		private void SetVisibility()
		{
			pnlVote.Visible = SignedInUser.Id != 0 && UserHasNoVotes();
			pnlInsertComment.Visible = SignedInUser.Id != 0;
			lblLoginToPost.Visible = SignedInUser.Id == 0;
		}

		/// <summary>
		/// Gets if user has no votes
		/// </summary>
		/// <returns></returns>
		private bool UserHasNoVotes()
		{
			if (SignedInUser.Id > 0 && selectedPhoto != null)
			{
				foreach (Vote vote in selectedPhoto.Votes)
				{
					if (vote.User.Id == SignedInUser.Id)
						return false;
				}
			}

			return true;
		}

		/// <summary>
		/// Fills photo fields
		/// </summary>
		private void InitializePhoto()
		{
			if (selectedPhoto != null)
			{
				lblPhotoName.Text = selectedPhoto.Name;
				imgDetail.ImageUrl = Page.ResolveUrl(Constants.detailPath + "/user" + selectedPhoto.Album.Owner.Id + "/" + selectedPhoto.Filename);
				lnkDetail.HRef = Page.ResolveUrl(Constants.basePath + "/user" + selectedPhoto.Album.Owner.Id + "/" + selectedPhoto.Filename);
				lblDescription.Text = selectedPhoto.Description;
				lblRatingValue.Text = GetAverageRating().ToString();
				lblVotesValue.Text = selectedPhoto.Votes.Count.ToString();
			}
		}

		/// <summary>
		/// Initializes comments
		/// </summary>
		private void InitializeComments()
		{
			if (selectedPhoto != null)
			{
				repCommnets.DataSource = selectedPhoto.Comments;
				repCommnets.DataBind();
			}
		}

		/// <summary>
		/// Initializes vote list
		/// </summary>
		private void InitializeVoteList()
		{
			ddlRating.Items.Add(1.ToString());
			ddlRating.Items.Add(2.ToString());
			ddlRating.Items.Add(3.ToString());
			ddlRating.Items.Add(4.ToString());
			ddlRating.Items.Add(5.ToString());
		}

		/// <summary>
		/// Counts average photo rating
		/// </summary>
		/// <returns></returns>
		private double GetAverageRating()
		{
			if (selectedPhoto != null)
			{
				double voteSum = 0;
				int voteCount = selectedPhoto.Votes.Count;
				if (voteCount > 0)
				{
					foreach (Vote vote in selectedPhoto.Votes)
					{
						voteSum += vote.Rating;
					}

					return Math.Round(voteSum / voteCount, 2);
				}
			}

			return 0;
		}

		#endregion
	}
}
